package com.eedi.framework.template.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.google.common.annotations.VisibleForTesting;
import com.eedi.framework.common.enums.CommonStatusEnum;
import com.eedi.framework.common.enums.UserTypeEnum;
import com.eedi.framework.common.pojo.PageResult;
import com.eedi.framework.common.util.collection.CollectionUtils;
import com.eedi.framework.common.util.object.BeanUtils;
import com.eedi.framework.template.controller.sys.vo.role.SysTemplateRolePageReq;
import com.eedi.framework.template.controller.sys.vo.role.SysTemplateRoleSimpleResp;
import com.eedi.framework.template.dal.dataobject.SysTemplateRoleDO;
import com.eedi.framework.template.dal.mapper.SysTemplateRoleMapper;
import com.eedi.framework.template.enums.SysTemplateRoleCodeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.eedi.framework.template.controller.sys.vo.role.SysTemplateRoleSaveReq;
import com.eedi.framework.template.enums.SysTemplateDataScopeEnum;
import com.eedi.framework.template.enums.SysTemplateRoleTypeEnum;
import com.eedi.framework.template.controller.sys.vo.role.SysTemplateRoleUpReq;
import javax.annotation.Resource;
import java.util.*;

import static com.eedi.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.eedi.framework.common.util.collection.CollectionUtils.convertMap;
import static com.eedi.framework.template.enums.SysTemplatePermissionErrorCodeConstants.*;

/**
 * 角色 Service 实现类
 *
 * @author 永聚长青源码
 */
@Service
@Slf4j
public class SysTemplateRoleServiceImpl implements SysTemplateRoleService {
    @Resource
    private SysTemplateRoleMapper sysTemplateRoleMapper;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public String createRole(SysTemplateRoleSaveReq createReqVO) {
        // 校验角色
        validateRoleDuplicate(createReqVO, null);
        // 插入到数据库
        SysTemplateRoleDO role = BeanUtils.toBean(createReqVO, SysTemplateRoleDO.class);
        role.setSysRoleType(SysTemplateRoleTypeEnum.CUSTOM);
        role.setSysRoleStatus(CommonStatusEnum.ENABLE);
        role.setSysRoleCode(SysTemplateRoleCodeEnum.DEFAULT.getCode());
        role.setSysRoleSort(0);
        // 默认可查看所有数据。原因是，可能一些项目不需要项目权限
        role.setSysRoleDataScope(SysTemplateDataScopeEnum.ALL);
        sysTemplateRoleMapper.insert(role);
        return role.getSysTemplateRoleId();
    }

    @Override
    public void updateRole(SysTemplateRoleUpReq updateReqVO) {
        // 校验是否可以更新
        validateRoleForUpdate(updateReqVO.getSysTemplateRoleId());
        // 校验角色的唯一字段是否重复
        validateRoleDuplicate(updateReqVO, updateReqVO.getSysTemplateRoleId());
        // 更新到数据库
        SysTemplateRoleDO updateObj = BeanUtils.toBean(updateReqVO, SysTemplateRoleDO.class);
        sysTemplateRoleMapper.updateById(updateObj);
    }

    @Override
    public void updateRoleStatus(String sysRoleId, CommonStatusEnum status) {
        // 校验是否可以更新
        validateRoleForUpdate(sysRoleId);

        // 更新状态
        SysTemplateRoleDO updateObj = new SysTemplateRoleDO().setSysTemplateRoleId(sysRoleId).setSysRoleStatus(status);
        sysTemplateRoleMapper.updateById(updateObj);
    }

    @Override
    public void updateRoleDataScope(String sysRoleId, SysTemplateDataScopeEnum dataScope, Set<String> dataScopeDeptIds) {
        // 校验是否可以更新
        validateRoleForUpdate(sysRoleId);

        // 更新数据范围
        SysTemplateRoleDO updateObject = new SysTemplateRoleDO();
        updateObject.setSysTemplateRoleId(sysRoleId);
        updateObject.setSysRoleDataScope(dataScope);
        updateObject.setSysRoleDataScopeDeptIds(dataScopeDeptIds);
        sysTemplateRoleMapper.updateById(updateObject);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteRole(String sysRoleId) {
        // 校验是否可以更新
        validateRoleForUpdate(sysRoleId);
        // 标记删除
        sysTemplateRoleMapper.deleteById(sysRoleId);
    }

    /**
     * 校验角色的唯一字段是否重复
     * <p>
     * 1. 是否存在相同名字的角色
     * 2. 是否存在相同编码的角色
     *
     * @param sysRoleSaveReq
     * @param roleId
     */
    @VisibleForTesting
    void validateRoleDuplicate(SysTemplateRoleSaveReq sysRoleSaveReq, String roleId) {
        // 0. 超级管理员、租户管理员，不允许创建
//        if (SysRoleCodeEnum.isImplAdmin(sysRoleSaveReq.getSysRoleCode()) || SysRoleCodeEnum.isSysAdmin(sysRoleSaveReq.getSysRoleCode())) {
//            throw exception(SYS_ROLE_ADMIN_CODE_ERROR, sysRoleSaveReq.getSysRoleCode());
//        }
        // 1. 该 name 名字被其它角色所使用
        SysTemplateRoleDO role = sysTemplateRoleMapper.selectByName(sysRoleSaveReq.getSysRoleName(), UserTypeEnum.MEMBER_SYS);
        if (role != null && !role.getSysTemplateRoleId().equals(roleId)) {
            throw exception(SYS_TEMPLATE_ROLE_NAME_DUPLICATE, sysRoleSaveReq.getSysRoleName());
        }
//        // 2. 是否存在相同编码的角色
//        if (!StringUtils.hasText(sysRoleSaveReq.getSysRoleCode())) {
//            return;
//        }
        // 该 code 编码被其它角色所使用
//        role = sysRoleMapper.selectByCode(sysRoleSaveReq.getSysRoleCode(), UserTypeEnum.MEMBER_SYS);
//        if (role != null && !role.getSysRoleId().equals(roleId)) {
//            throw exception(SYS_ROLE_CODE_DUPLICATE, sysRoleSaveReq.getSysRoleCode());
//        }
    }

    /**
     * 校验角色的唯一字段是否重复
     * <p>
     * 1. 是否存在相同名字的角色
     * 2. 是否存在相同编码的角色
     *
     * @param sysRoleSaveReq
     * @param roleId
     */
    @VisibleForTesting
    void validateRoleDuplicate(SysTemplateRoleUpReq sysRoleSaveReq, String roleId) {
        // 0. 超级管理员、租户管理员，不允许创建
//        if (SysRoleCodeEnum.isImplAdmin(sysRoleSaveReq.getSysRoleCode()) || SysRoleCodeEnum.isSysAdmin(sysRoleSaveReq.getSysRoleCode())) {
//            throw exception(SYS_ROLE_ADMIN_CODE_ERROR, sysRoleSaveReq.getSysRoleCode());
//        }
        // 1. 该 name 名字被其它角色所使用
        SysTemplateRoleDO role = sysTemplateRoleMapper.selectByName(sysRoleSaveReq.getSysRoleName(), UserTypeEnum.MEMBER_SYS);
        if (role != null && !role.getSysTemplateRoleId().equals(roleId)) {
            throw exception(SYS_TEMPLATE_ROLE_NAME_DUPLICATE, sysRoleSaveReq.getSysRoleName());
        }
        // 2. 是否存在相同编码的角色
//        if (!StringUtils.hasText(sysRoleSaveReq.getSysRoleCode())) {
//            return;
//        }
        // 该 code 编码被其它角色所使用
//        role = sysRoleMapper.selectByCode(sysRoleSaveReq.getSysRoleCode(), UserTypeEnum.MEMBER_SYS);
//        if (role != null && !role.getSysRoleId().equals(roleId)) {
//            throw exception(SYS_ROLE_CODE_DUPLICATE, sysRoleSaveReq.getSysRoleCode());
//        }
    }

    /**
     * 校验角色是否可以被更新
     *
     * @param roleId 角色编号
     */
    @VisibleForTesting
    void validateRoleForUpdate(String roleId) {
        SysTemplateRoleDO sysRoleDO = sysTemplateRoleMapper.selectById(roleId);
        if (sysRoleDO == null) {
            throw exception(SYS_TEMPLATE_ROLE_NOT_EXISTS);
        }
        // 内置角色，不允许删除
        if (SysTemplateRoleTypeEnum.SYSTEM.equals(sysRoleDO.getSysRoleType())) {
            throw exception(SYS_TEMPLATE_ROLE_CAN_NOT_UPDATE_SYSTEM_TYPE_ROLE);
        }
    }

    @Override
    public SysTemplateRoleDO getRole(String roleId) {
        return sysTemplateRoleMapper.selectById(roleId);
    }

    @Override
    public SysTemplateRoleDO getRoleFromCache(String sysRoleId) {
        return sysTemplateRoleMapper.selectById(sysRoleId);
    }


    @Override
    public List<SysTemplateRoleDO> getRoleListByStatus(Collection<CommonStatusEnum> statuses) {
        return sysTemplateRoleMapper.selectListByStatus(statuses);
    }

    @Override
    public List<SysTemplateRoleDO> getRoleList() {
        return sysTemplateRoleMapper.selectList();
    }

    @Override
    public List<SysTemplateRoleDO> getRoleList(Collection<String> roleIds) {
        if (CollectionUtil.isEmpty(roleIds)) {
            return Collections.emptyList();
        }
        return sysTemplateRoleMapper.selectBatchIds(roleIds);
    }

    @Override
    public List<SysTemplateRoleSimpleResp> getRoleSimpleList(Collection<String> sysRoleIds) {
        return sysTemplateRoleMapper.selectByRoleIds(sysRoleIds);
    }

    @Override
    public List<SysTemplateRoleDO> getRoleListFromCache(Collection<String> roleIds) {
        if (CollectionUtil.isEmpty(roleIds)) {
            return Collections.emptyList();
        }
        // 这里采用 for 循环从缓存中获取，主要考虑 Spring CacheManager 无法批量操作的问题
        SysTemplateRoleServiceImpl self = getSelf();
        return CollectionUtils.convertList(roleIds, self::getRoleFromCache);
    }

    @Override
    public PageResult<SysTemplateRoleDO> getRolePage(SysTemplateRolePageReq reqVO) {
        return sysTemplateRoleMapper.selectPage(reqVO);
    }

    @Override
    public boolean hasAnySuperAdmin(Collection<String> roleIds) {
        if (CollectionUtil.isEmpty(roleIds)) {
            return false;
        }
        SysTemplateRoleServiceImpl self = getSelf();
        return roleIds.stream().anyMatch(roleId -> {
            SysTemplateRoleDO role = self.getRoleFromCache(roleId);
            return role != null
                    && (SysTemplateRoleCodeEnum.isImplAdmin(role.getSysRoleCode())
                    || SysTemplateRoleCodeEnum.isSysAdmin(role.getSysRoleCode()));
        });
    }

    @Override
    public void validateRoleList(Collection<String> roleIds) {
        if (CollUtil.isEmpty(roleIds)) {
            return;
        }
        // 获得角色信息
        List<SysTemplateRoleDO> roles = sysTemplateRoleMapper.selectBatchIds(roleIds);
        Map<String, SysTemplateRoleDO> roleMap = convertMap(roles, SysTemplateRoleDO::getSysTemplateRoleId);
        // 校验
        roleIds.forEach(roleId -> {
            SysTemplateRoleDO role = roleMap.get(roleId);
            if (role == null) {
                throw exception(SYS_TEMPLATE_ROLE_NOT_EXISTS);
            }
            if (!CommonStatusEnum.ENABLE.equals(role.getSysRoleStatus())) {
                throw exception(SYS_TEMPLATE_ROLE_IS_DISABLE, role.getSysRoleName());
            }
        });
    }

    @Override
    public List<SysTemplateRoleSimpleResp> getRoleByCode(String sysRoleCode) {
        if (StrUtil.isBlank(sysRoleCode)) {
            return List.of();
        }
        return sysTemplateRoleMapper.getByCode(sysRoleCode);
    }



    /**
     * 获得自身的代理对象，解决 AOP 生效问题
     *
     * @return 自己
     */
    private SysTemplateRoleServiceImpl getSelf() {
        return SpringUtil.getBean(getClass());
    }

}
